package com.daxia.bumall.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.daxia.bumall.common.ProfitType;
import com.daxia.bumall.common.UserType;
import com.daxia.bumall.dao.ProfitDAO;
import com.daxia.bumall.dto.CompanyDTO;
import com.daxia.bumall.dto.ProfitDTO;
import com.daxia.bumall.dto.UserDTO;
import com.daxia.bumall.model.Profit;
import com.daxia.bumall.model.User;
import com.daxia.bumall.support.Page;
import com.daxia.bumall.util.BeanMapper;

@Service
public class ProfitService extends BaseService {
	private static Logger logger = Logger.getLogger(ProfitService.class);
	
	@Autowired
	private ProfitDAO profitDAO;
	@Autowired
	private CompanyService companyService;
	@Autowired
	private UserService userService;
	@Autowired
	private DispatcherService dispatcherService;
	
	public List<ProfitDTO> find(ProfitDTO query, Page page) {
		List<Profit> models = profitDAO.find(query, page);
		List<ProfitDTO> dtos = toDTOs(models);
		return dtos;
	}
	
	public List<ProfitDTO> findAll() {
		return this.find(new ProfitDTO(), null);
	}
	
	public List<ProfitDTO> find(int count) {
		Page page = new Page();
		page.setPage(1);
		page.setPageSize(count);
		return this.find(new ProfitDTO(), page);
	}
	
	public Long create(ProfitDTO dto) {
		Profit model = new Profit();
		toModel(model, dto);
		return profitDAO.create(model);
	}
	
	public ProfitDTO load(Long id) {
	    Profit model = profitDAO.load(id);
	    return toDTO(model);
    }

	public void updateAllFields(ProfitDTO dto) {
		Profit model = profitDAO.load(dto.getId());
		toModel(model, dto);
		profitDAO.update(model);
    }

	public void deleteByIds(Long[] ids) {
		if (ids != null) {
			for (Long id : ids) {
				throw new RuntimeException("未实现删除逻辑，请确认是物理删除还是逻辑删除");
				// profitDAO.deleteById(id);
			}
		}
    }
	
	public void deleteById(Long id) {
		this.deleteByIds(new Long[] {id});
	}

	public ProfitDTO findOne(ProfitDTO query) {
		Profit model = profitDAO.findOne(query);
		return toDTO(model);
	}
	
	private List<ProfitDTO> toDTOs(List<Profit> models) {
		if (CollectionUtils.isEmpty(models)) {
			return new ArrayList<ProfitDTO>(0);
		}
		List<ProfitDTO> dtos = new ArrayList<ProfitDTO>(models.size());
		for (Profit model : models) {
	        ProfitDTO dto = toDTO(model);
	        dtos.add(dto);
        }
	    return dtos;
    }
    
    private ProfitDTO toDTO(Profit model) {
		if (model == null) {
			return null;
		}
		ProfitDTO dto = BeanMapper.map(model, ProfitDTO.class);
		
		return dto;
	}
	
	private void toModel(Profit model, ProfitDTO dto) {
		BeanMapper.copy(dto, model);
    }
	
	@SuppressWarnings("unused")
	private List<Profit> toModels(List<ProfitDTO> dtos) {
		if (CollectionUtils.isEmpty(dtos)) {
			return new ArrayList<Profit>(0);
		}
		List<Profit> models = new ArrayList<Profit>(dtos.size());
		for (ProfitDTO dto : dtos) {
	        Profit model = new Profit();
	        toModel(model, dto);
	        models.add(model);
        }
		return models;
	}

	public Double findProfitByCompany(Long companyId) {
		CompanyDTO c = companyService.load(companyId);
		if (c.getCreator() == null) {
			return null;
		}
		ProfitDTO query = new ProfitDTO();
		query.setType(ProfitType.AddCompany.getValue());
		query.setUser(c.getCreator());
		query.setSubAccountUserId(c.getUser());
		ProfitDTO p = this.findOne(query);
		if (p == null) {
			return null;
		}
		return p.getAmount();
	}
	
	/**
	 * 修复利润
	 */
	@Transactional
	public void fixProfit() {
		if (logger.isDebugEnabled()) {
			logger.debug("fix profit...");
		}
		// find all city operator
		List<UserDTO> cityOperators = userService.findByType(UserType.City);
		if (logger.isDebugEnabled()) {
			logger.debug("" + cityOperators.size() + " cityOperators");
		}
		// find their children
		for (UserDTO co : cityOperators) {
			List<UserDTO> children = userService.findSubAccounts(co.getId(), null);
			if (logger.isDebugEnabled()) {
				logger.debug(children.size() + " children");
			}
			for (UserDTO child : children) {
				child.setParent(new User(co.getId()));
				userService.updateAllFields(child);
				
				if (child.getType() == UserType.DecorateCompany.getValue()) {
					dispatcherService.onCompanyActivated(child.getId());
				}
			}
		}
		// if child is a company
			// then check if has profit record
	}

	public ProfitDTO findByTypeAndSubAccountUserId(ProfitType type, Long userId) {
		ProfitDTO query = new ProfitDTO();
		query.setType(type.getValue());
		query.setSubAccountUserId(new User(userId));
		return this.findOne(query);
	}

	public double totalProfitByTypeAndUser(ProfitType type, Long userId, Date start, Date end) {
		return profitDAO.totalProfitByTypeAndUser(type, userId, start, end);
	}
}
